package com.iplatform.iplatformuser.framework.privilege.annotation;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

/**
* Title: MyBatiesInterceptor
* Description:   添加了自定义注解后，针对SQL做数据包权限过滤
* @author RayLLi
* @date 2019年6月25日
 */
@Component
@Order(Integer.MAX_VALUE)
@Intercepts({
        @Signature(
                type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class
        })
})
public class MyBatiesInterceptor implements Interceptor {

	private static final Logger LOG = LoggerFactory.getLogger(MyBatiesInterceptor.class);

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
				SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
		// 先拦截到RoutingStatementHandler，里面有个StatementHandler类型的delegate变量，其实现类是BaseStatementHandler，然后就到BaseStatementHandler的成员变量mappedStatement
		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

		//TODO 预留路径白名单
		// id为执行的mapper方法的全路径名，如com.uv.dao.UserMapper.insertUser
		// String id = mappedStatement.getId();

		//TODO 预留语句类型过滤
		// sql语句类型 select、delete、insert、update
		// String sqlCommandType = mappedStatement.getSqlCommandType().toString();

		BoundSql boundSql = statementHandler.getBoundSql();
		// 获取到原始sql语句
		String mSql = boundSql.getSql();

		// 注解逻辑判断 添加注解了才拦截
		Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf(".")));
		String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length());
		for (Method method : classType.getDeclaredMethods()) {
			if (method.isAnnotationPresent(MybatiesInterceptAnnotation.class) && mName.equals(method.getName())) {
				MybatiesInterceptAnnotation interceptorAnnotation = method.getAnnotation(MybatiesInterceptAnnotation.class);
				if (interceptorAnnotation.flag()) {
					System.out.println("============="+mSql);
					LOG.debug("--------->mSql:"+mSql);
				}
			}
		}

		// 通过反射修改sql语句
		Field field = boundSql.getClass().getDeclaredField("sql");
		field.setAccessible(true);
		field.set(boundSql, mSql);
		return invocation.proceed();

	}

	@Override
	public Object plugin(Object target) {
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}

	}

	@Override
	public void setProperties(Properties properties) {
		 LOG.warn("MyBatiesInterceptor配置完毕!");
	}

}